[Amazon Lex] バリデーションのLambdaから動的に生成したレスポンスカードを返してみる
1 はじめに
こんにんちは、AIソリューション部の平内(SIN)です。
Amazon Lex(以下、Lex)では、レスポンスに画像やボタンを含んだカードを返すことができます。
今回は、このようなレスポンスカードをLambdaで動的に生成して返す要領を確認してみました。
なお、Lambdaの実装では、ライブラリとしてLex SDKを使用しています。
[Amazon Lex] Alexa SDK V2 みたいに書けるSDKを雑に作ってみました
Lex SDKは、Lexのコードを、Alexa SDK Ver2のように書けるので、既にAlexaの開発に関わっている方には、Lex開発のハードルがかなり低くなるのでは無いかと思います。また、TypeScriptでも書けますので、慣れない、Lexのオブジェクトが.(ドット)を打つだけで表示できて超便利です。(ステマ)
2 コンソールから設定する場合
レスポンスカードは、コードで生成しなくても、AWSコンソールから簡単に追加できます。
コンソールから設定する場合は、下記のように、当該スロットのSettingsを開きます。
カードの情報は、次のようなUIで追加することになります。
しかし、この要領では、表示する画像やメッセージ、そして、ボタンの種類や数は、ボットの設計時に決定され固定となってしまいます。
3 コードから設定する場合
(1) バリデーションLambda
コードで実装する場合は、initialization and varidation code hookで指定したLambdaの中で行ないます。
(2) ElicitSlot
Lambdaのレスポンスで、dialogActionのtype が、ElicitSlotである時、指定されたスロットを取得するモードとなり、このレスポンスにResponseCardのオブジェクトを含めることができます。
Lambda Function Input Event and Response Format より
(3) Lex SDK
Lex SDKでは、ResponseBuilderのgetElicitSlotResponse()メソッドで、ElicitSlotを返すレスポンスを返すことができます。
class ResponseBuilder { getElicitSlotResponse(sessionAttributes, intentName, slots, slotToElicit, message, responseCard) { return { sessionAttributes: sessionAttributes, dialogAction: { type: DialogActionType.ElicitSlot, intentName: intentName, slots: slots, slotToElicit: slotToElicit, message: message, responseCard: responseCard } }; } ・・・略・・・
このため、下記のように、InvocationSourceが、DialogCodeHookであり、かつ、Flowerスロットに、まだ値が入っていない時に、カードを返すように実装しています。
if (h.source === Lex.InvocationSource.DialogCodeHook) { if(!flowerType) { const responseCard: Lex.ResponseCard = { genericAttachments:[ { title: "TITLE", imageUrl: imageUrl, buttons:[...], } ] } return h.responseBuilder.getElicitSlotResponse( ... responseCard) } return h.responseBuilder .getDelegateResponse(h.attributes, h.slots)
4 実装コード
実装した全てのコードは、下記のようになりました。簡略化のため、エラーハンドは省略されています。
import * as Lex from 'lex-sdk'; let bot: Lex.Bot; declare var exports: any; exports.handler = async function (event: Lex.IntentRequest, context: any) { console.log(JSON.stringify(event)); if (!bot) { bot = Lex.BotBuilder() .addRequestHandlers( OrderIntentHandler,OrderIntentHandler) .create(); } return bot.invoke(event, context); } const OrderIntentHandler: Lex.RequestHandler = { canHandle(h: Lex.HandlerInput) { return (h.intentName == 'OrderFlowers') }, handle(h: Lex.HandlerInput) { const flowerType = h.slots['FlowerType']; const date = h.slots['PickupDate']; const time = h.slots['PickupTime']; if (h.source === Lex.InvocationSource.DialogCodeHook) { if(!flowerType) { const message = { contentType: Lex.ContentType.PlainText, content: `What type of flowers would you like to order?` }; const imageUrl = 'https://d1eju4ngjniac3.cloudfront.net/OrderFlower.png'; const responseCard: Lex.ResponseCard = { version: "001", contentType : Lex.CardContentType.Generic, genericAttachments:[ { title: "TITLE", subTitle: "SubTitle", imageUrl: imageUrl, attachmentLinkUrl: imageUrl, buttons:[ {text:'roses',value:'roses'}, {text:'tulips',value:'tulips'}, {text:'lilies',value:'lilies'}, ], } ] } return h.responseBuilder .getElicitSlotResponse(h.attributes,h.intentName,h.slots,'FlowerType', message, responseCard) } return h.responseBuilder .getDelegateResponse(h.attributes, h.slots) } else { // FulfillmentCodeHook const message = { contentType: Lex.ContentType.PlainText, content: `Thanks, your order for ${flowerType} has been placed and will be ready for pickup by ${time} on ${date}` }; return h.responseBuilder .getCloseResponse( h.attributes, Lex.FulfillmentState.Fulfilled, message) } } }
5 最後に
今回は、レスポンスカードをLambdaで動的に生成して返す要領を確認してみました。 カードを使用すると、明確に選択内容をユーザーに示すことができ、また、ボタンでのレスポンスも可能になります。
UX向上に非常に有効なレスポンスカードをコードから生成することで、状況に応じたきめ細かいユーザー体験が可能になるかも知れません。
Lex SDKを使用すると、レスポンスカードも簡単に記述できました。(すいません、しつこくステマです)
画像は、下記のものを利用させて頂きました。
弊社ではAmazon Connectのキャンペーンを行なっております。
3月に引き続き、4月も「無料Amazon Connectハンズオンセミナー」を開催致します。導入を検討されておられる方は、是非、お申し込み下さい。
また音声を中心とした各種ソリューションの開発支援も行なっております。